package main

/*
1.13版本之前的错误处理
1.13版本之前只有前面讲的 errors.New(),fmt.Errorf() 两种方法
处理错误的时候我们通常会使用这些方法添加一些额外的信息，记录错误的上下文一年后续排查：

	if err!=nil{
		return fmt.Errorf("错误上下文 %v :%v",name,err)
	}

但是 fmt.Errorf() 方法（上述两种方法）会创建一个包含有原始错误文本信息的新的error，但是与原始错误之间 没有任何关联的。
然而我们有时候是需要保留这种关联性的，这时候就需要我们自己去定义一个包含有原始错误的新的错误类型，比如自定义一个QueryError:

	type QueryError struct{
		Query string
		Err error   //与原始错误关联
	}

然后可以判断这个原始错误是否为某个特定的错误，比如 ErrPermission:

	if e,ok :=err.(*QueryError);ok && e.Err == ErrPermission{
		//query failed because of a permission problem
	}

写到这里发现 对于错误的关联嵌套情况处理起来还是比较麻烦的，而 Go 1.13 版本对此进行了改进。
1.13 版本之后的错误处理
首先要说明是 Go是向后兼容的，上文中的1.13 版本之前的用法完全可以继续使用。
1.13版本的改进内容：
新增方法1 errors.Unwrap
func Unwrap(err error) error
对于错误嵌套的情况，Unwrap 方法可以用来返回某个错误所包含的底层错误，
例如 e1 包含了e2 这里 Unwrap e1 就可以得到 e2 。Unwrap 支持链式调用（处理错误的多层嵌套）
新增方法2 errors.Is
func Is(err,target error) bool
新增方法3:errors.As
func As(err error, target interface{}) bool

使用 errors.Is 和 errors.As 方法检查错误：
errors.Is 方法检查值：

	if errors.Is(err, ErrNotFound){
		//something wasn't found
	}

errors.As 方法检查错误类型：

var e *QueryError

	if errors.As(err.&e){
		//err is a *QueryError ,and e is set to the error’s value
	}

errors.Is 方法会对嵌套的情况展开判断，这意味着：

	if e,ok := err.(*QueryError); ok && e.Err == ErrPermission{
		//err,or some error that it wraps ,is a permission problem
	}

新增4： fmt.Errorf 新增了 %w 格式化动词
fmt.Errorf 方法增加了%w 格式化动词，其返回的 error 自动实现了 Unwrap 方法
fmt.Errorf 方法通过 %w 包装错误：

	if err!= nil{
		return fmt.Errorf("错误上下文 %v: %v",name,err)
	}

上面代码通过%v 返回了一个语言是错误无法关联的新错误。
我们使用 %w 就可以进行关联了：

	if err!=nil{
		//Return an error which unwtaps to err
		return fmt.Errorf("错误上下文 %v: %w"，name,err)
	}

一旦使用了 %w 进行关联 就可以使用 errors.Is 和 errors.As 方法了：
err:= fmt.Errorf("access denied: %w",ErrPermission)
...
if(errors.Is(err,ErrPermission))...

对于是否包装错误以及如何包装错误并没有统一的答案。
*/
func main() {

}
